Введение
Метилирование ДНК играет важную роль в регуляции экспрессии генов
млекопитающих. Метилирование промотора, как правило, инактивирует
экспрессию группы рядом расположенных генов, так как транскрипционные
факторы не могут связаться с промотором вследствие как прямого
стереохимического влияния метильной группы, так и изменения
пространственной структуры хроматина. ДНК метилируется по остаткам
цитозина по атому углерода в 5 положении с помощью специальных ферментов
ДНК-метилтрансфераз. Цитозины метилируются в большинстве своём в
специальных областях, богатыми CG-динуклеотидами. Такие области называют
CpG-островки.
Исследование метилирования генов в онкологии помогает понять природу
изменений в опухолевой ткани, выделить подтипы опухолей в соответствии с
которыми можно подбирать терапевтические агенты. Методов, измеряющих
метилирование ДНК, изобретено большое количество. В этом мастер-классе
мы поговорим о бисульфитном секвенировании с уменьшенной
представленностью (Reduced Representation Bisulfite Sequencing,
RRBS).
Внимание: методы и подходы, рассказываемые
в этом блокноте также применимы к полногеномному бисульфитному
секвенированию (Whole Genome Bisulfite Sequencing, WGBS). Данный блокнот
не претендует на истину в последней инстанции. Существуют альтернативные
подходы к анализу и соответствующие программы и библиотеки.
RRBS
RRBS - бисульфитное секвенирование с уменьшенной представленностью.
Оно более дешевое, чем секвенирование полного генома, но даёт информацию
более, чем о 80% CpG островках человеческого генома. Достигается этот
эффект за счёт обогащения библиотеки специальными рестриктазами (MspI,
XmaI).
Библиотеки в процессе подготовки к секвенированию подвергают
бисульфитной конверсии, т.е. обрабатывают раствором NaHSO3 .
Суть этого шага, представлена на рисунке @ref(fig:bisulfite).
Неметилированные цитозины при обработке бисульфитом натрия окисляются до
урацила, который при ПЦР заменяется на тимин. Однако такому не
подвержены метилированные цитозины. Следовательно, на том месте, где
секвенатором получен тимин, был неметилированный цитозин, а процитанные
цитозины - метилированные. Таким образом, можно измерять уровень
метилирования в конкретном локусе ДНК.
Уровень метилирования рассчитывается по следующей формуле:
\[
methylation = \frac{C}{C+T}
\]
Анализ данных
Последовательность обработки данных представлена рисунке
@ref{fig:workflow} (Wreczycka et al.
2017).
Контроль качества осуществляется с помощью стандартной программы
FastQC.
library(DiagrammeR)
mermaid("
graph LR
A{}-->B
")
Подготовка к работе
if (!require("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install(c("GEOquery","limma", "edgeR", "methylKit", "DMRcate"))
install.packages(c("stringr", "plyr"))
Импорт пакетов
Загрузка данных
# Чтобы загрузка не падала из-за временного ограничения на обмен между сервером и клиентом (вами)
options(timeout = max(300, getOption("timeout")))
options(download.file.method.GEOquery = "wget")
experiment = GEOquery::getGEO("GSE122799")[[1]]
untar("GSE122799/GSE122799_RAW.tar", exdir = "GSE122799/")
files = Sys.glob("GSE122799/*.bismark.cov.gz")
sample.include = which(phenotypes$characteristics_ch1.2 == "mtypehe: hiHER" | phenotypes$characteristics_ch1.2 == "mtypehe: hiLumAB")
phenotypes1 = phenotypes[sample.include, ]
files1 = files[sample.include]
Описательная статистика
getMethylationStats(raw_data[[2]],plot=TRUE,both.strands=FALSE)
getCoverageStats(raw_data[[2]],plot=TRUE,both.strands=FALSE)
for (sample in raw_data) {
getMethylationStats(sample,plot=TRUE,both.strands=FALSE)
Sys.sleep(5)
}
filtered = filterByCoverage(raw_data,lo.count=10,lo.perc=NULL,
hi.count=NULL,hi.perc=99.5)
Объединение результатов
meth=methylKit::unite(filtered, destrand=FALSE,min.per.group = 10L, mc.cores = 30)
#load("Unite_meth.RData")
Фильтрация
methMatrix = percMethylation(meth,rowids = T)
sds=matrixStats::rowSds(methMatrix,na.rm = T)
print(dim(methMatrix))
hist(sds,col="cornflowerblue",xlab="Std. dev. per CpG", breaks = 50)
dim(meth)
meth.filt = meth[sds > 10,]
dim(meth.filt)
shared = with(
list(xx = ifelse(is.na(methMatrix), 0, 1), n = ncol(methMatrix)),
ldply(
1:(n-1),
function(i)
{
# построим список каждый-с-каждым
ddply(
data.frame("i"=rep(i, n-i), "j"=(i+1):n),
c("i","j"),
function(row){
i <- row[1,1]; j <- row[1,2];
sum(xx[,i] * xx[,j]);
});
},.parallel=TRUE))
print(shared[shared$V1 <= 10000,])
miss = function(x){
sum(is.na(x))/(sum(!is.na(x))+sum(is.na(x)));
}
meth.filt.mat = percMethylation(meth.filt)
miss_x <- miss(methMatrix);
max_miss = 0.2
while (miss_x > max_miss) {
xx = ifelse(is.na(meth.filt), 0, 1);
# в скольких образцах есть данные по каждому локусу
cvrg_c = apply(xx, 1, sum);
cvrg_c_mean = mean(cvrg_c);
cvrg_c_sd = sd(cvrg_c);
filter_out_plan = nrow(meth.filt)*(miss_x - max_miss);
cvrg_c_thrsh = cvrg_c[tail(head(order(cvrg_c), filter_out_plan) ,1)];
cvrg_c_flt = cvrg_c <= cvrg_c_thrsh;
meth.filt = meth.filt[!cvrg_c_flt, ];
meth.filt.mat = percMethylation(meth.filt)
miss_x = miss(meth.filt);
cat(sprintf(
"Filters out: #plan=%f, #fact=%d CpGs ==> Dim: %d x %d (samples x CpGs); miss(x) = %.4f \n",
filter_out_plan, sum(cvrg_c_flt), dim(meth.filt.mat)[2], dim(meth.filt.mat)[1], miss_x ));
}
Анализ после фильтрации
png(width = 2400, height = 2400, filename = "correlation.png")
getCorrelation(meth.filt, plot = T)
dev.off()
PCASamples(meth.filt)
PCASamples(meth.filt, screeplot = T)
tree = clusterSamples(meth.filt, dist = "correlation", method="ward.D2")
rect.hclust(tree, k = 2, border = "darkgreen")
DMR
meth.diff = calculateDiffMeth(meth.filt, overdispersion = "MN",
adjust = "fdr",
test = "F",
mc.cores = 30)
meth.diff$dif.met = ifelse(meth.diff$meth.diff <= -20 & meth.diff$qvalue <= 0.05,
"HYPO",
ifelse(meth.diff$meth.diff >= 20 & meth.diff$qvalue <= 0.05,
"HYPER",
"NO"))
methylKit::bedgraph(meth.diff,"meth_diff.bedgraph",col.name = "meth.diff")
signif.diff = getMethylDiff(meth.diff,qvalue = 0.05, difference = 20)
diff.df = do.call(cbind.data.frame, meth.diff@.Data)
colnames(diff.df) = c("chr", "start", "end", "strand", "pvalue", "qvalue", "meth.diff", "dif.met")
ggplot(data=diff.df, aes(x=meth.diff, y=-log10(pvalue), col=dif.met)) +
geom_point() +
theme_minimal() +
scale_color_manual(values=c("HYPO"="blue", "NO"="black", "HYPER"="green")) +
geom_vline(xintercept=c(-20, 20), col="red") +
geom_hline(yintercept=-log10(0.05), col="red")
rownames = paste(signif.diff$chr,signif.diff$start,signif.diff$end,sep = ".")
counts.dif.met = percMethylation(meth.filt,rowids = T)[rownames,]
ann_col_df = as.data.frame(phenotypes1$characteristics_ch1.2)
colnames(ann_col_df) = "Phenotype"
ann_col_df$Phenotype = as.factor(ann_col_df$Phenotype)
levels(ann_col_df$Phenotype) = c("hiHER","hiLumAB")
row.names(ann_col_df) = phenotypes1$geo_accession
ann_col_df
ann_colors = list(Phenotype = c("hiHER"="red", "hiLumAB"="orange"))
pheatmap::pheatmap(counts.dif.met,
color = colorRampPalette(c("white","cyan", "blue"))(100),
clustering_distance_rows = "manhattan",
clustering_distance_cols = "manhattan",
clustering_method = "ward.D2",
scale = "none",
annotation_col = ann_col_df,
annotation_colors = ann_colors,
treeheight_row = 100,
treeheight_col = 75)
require(genomation)
gene.obj=readTranscriptFeatures("refseq.hg19.bed.txt")
gene.parts = annotateWithGeneParts(as(signif.diff,"GRanges"),gene.obj)
cpg.obj=readFeatureFlank("cpgi.hg19.bed.txt",
feature.flank.name=c("CpGi","shores"))
diffCpGann=annotateWithFeatureFlank(as(signif.diff,"GRanges"),
cpg.obj$CpGi,cpg.obj$shores,
feature.name="CpGi",flank.name="shores")
library("org.Hs.eg.db")
promoters = gene.parts@dist.to.TSS[gene.parts@members[,1] == 1,]
cols <- c("ENTREZID","GENENAME","SYMBOL", "GENENAME")
annotation = AnnotationDbi::select(org.Hs.eg.db, keys=unique(promoters$feature.name), columns=cols, keytype="REFSEQ")
coord_promoters = cbind.data.frame(promoters, signif.diff[promoters$target.row,])
annotated_promoters = coord_promoters %>% dplyr::inner_join(annotation, by=c('feature.name'='REFSEQ'))
write.csv2(annotated_promoters, file = "promoters.csv")
Rgraphviz
genesOfInterest = annotated_promoters$meth.diff
names(genesOfInterest) = annotated_promoters$ENTREZID
genesOfInterest = sort(genesOfInterest,decreasing = T)
go <- clusterProfiler::enrichGO(gene=annotated_promoters$ENTREZID,
ont ="BP",
keyType = "ENTREZID",
pvalueCutoff = 0.1,
OrgDb = org.Hs.eg.db,
pAdjustMethod = "fdr",
readable = T)
head(go)
dotplot(go)
Wreczycka, Katarzyna, Alexander Gosdschan, Dilmurat Yusuf, Björn
Grüning, Yassen Assenov, and Altuna Akalin. 2017.
“Strategies for
Analyzing Bisulfite Sequencing Data.” Journal of
Biotechnology 261 (November): 105–15.
https://doi.org/10.1016/j.jbiotec.2017.08.007.
LS0tCnRpdGxlOiAi0JDQvdCw0LvQuNC3INC00LDQvdC90YvRhSBSUkJTLXNlcSIKYXV0aG9yOiAi0KHQvNC40YDQvdC+0LIg0JDQvdGC0L7QvSDQodC10YDQs9C10LXQstC40YciCmRhdGU6ICIyMi4wNS4yMDI0Igpib29rZG93bjo6aHRtbF9kb2N1bWVudDI6IGh0bWxfbm90ZWJvb2sKZmlnLWNhcHRpb246IHRydWUKYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYgotLS0KCiMg0JLQstC10LTQtdC90LjQtQoK0JzQtdGC0LjQu9C40YDQvtCy0LDQvdC40LUg0JTQndCaINC40LPRgNCw0LXRgiDQstCw0LbQvdGD0Y4g0YDQvtC70Ywg0LIg0YDQtdCz0YPQu9GP0YbQuNC4INGN0LrRgdC/0YDQtdGB0YHQuNC4INCz0LXQvdC+0LIg0LzQu9C10LrQvtC/0LjRgtCw0Y7RidC40YUuINCc0LXRgtC40LvQuNGA0L7QstCw0L3QuNC1INC/0YDQvtC80L7RgtC+0YDQsCwg0LrQsNC6INC/0YDQsNCy0LjQu9C+LCDQuNC90LDQutGC0LjQstC40YDRg9C10YIg0Y3QutGB0L/RgNC10YHRgdC40Y4g0LPRgNGD0L/Qv9GLINGA0Y/QtNC+0Lwg0YDQsNGB0L/QvtC70L7QttC10L3QvdGL0YUg0LPQtdC90L7Qsiwg0YLQsNC6INC60LDQuiDRgtGA0LDQvdGB0LrRgNC40L/RhtC40L7QvdC90YvQtSDRhNCw0LrRgtC+0YDRiyDQvdC1INC80L7Qs9GD0YIg0YHQstGP0LfQsNGC0YzRgdGPINGBINC/0YDQvtC80L7RgtC+0YDQvtC8INCy0YHQu9C10LTRgdGC0LLQuNC1INC60LDQuiDQv9GA0Y/QvNC+0LPQviDRgdGC0LXRgNC10L7RhdC40LzQuNGH0LXRgdC60L7Qs9C+INCy0LvQuNGP0L3QuNGPINC80LXRgtC40LvRjNC90L7QuSDQs9GA0YPQv9C/0YssINGC0LDQuiDQuCDQuNC30LzQtdC90LXQvdC40Y8g0L/RgNC+0YHRgtGA0LDQvdGB0YLQstC10L3QvdC+0Lkg0YHRgtGA0YPQutGC0YPRgNGLINGF0YDQvtC80LDRgtC40L3QsC4g0JTQndCaINC80LXRgtC40LvQuNGA0YPQtdGC0YHRjyDQv9C+INC+0YHRgtCw0YLQutCw0Lwg0YbQuNGC0L7Qt9C40L3QsCDQv9C+INCw0YLQvtC80YMg0YPQs9C70LXRgNC+0LTQsCDQsiA1INC/0L7Qu9C+0LbQtdC90LjQuCDRgSDQv9C+0LzQvtGJ0YzRjiDRgdC/0LXRhtC40LDQu9GM0L3Ri9GFINGE0LXRgNC80LXQvdGC0L7QsiDQlNCd0Jot0LzQtdGC0LjQu9GC0YDQsNC90YHRhNC10YDQsNC3LiDQptC40YLQvtC30LjQvdGLINC80LXRgtC40LvQuNGA0YPRjtGC0YHRjyDQsiDQsdC+0LvRjNGI0LjQvdGB0YLQstC1INGB0LLQvtGR0Lwg0LIg0YHQv9C10YbQuNCw0LvRjNC90YvRhSDQvtCx0LvQsNGB0YLRj9GFLCDQsdC+0LPQsNGC0YvQvNC4IENHLdC00LjQvdGD0LrQu9C10L7RgtC40LTQsNC80LguINCi0LDQutC40LUg0L7QsdC70LDRgdGC0Lgg0L3QsNC30YvQstCw0Y7RgiBDcEct0L7RgdGC0YDQvtCy0LrQuC4KCtCY0YHRgdC70LXQtNC+0LLQsNC90LjQtSDQvNC10YLQuNC70LjRgNC+0LLQsNC90LjRjyDQs9C10L3QvtCyINCyINC+0L3QutC+0LvQvtCz0LjQuCDQv9C+0LzQvtCz0LDQtdGCINC/0L7QvdGP0YLRjCDQv9GA0LjRgNC+0LTRgyDQuNC30LzQtdC90LXQvdC40Lkg0LIg0L7Qv9GD0YXQvtC70LXQstC+0Lkg0YLQutCw0L3QuCwg0LLRi9C00LXQu9C40YLRjCDQv9C+0LTRgtC40L/RiyDQvtC/0YPRhdC+0LvQtdC5INCyINGB0L7QvtGC0LLQtdGC0YHRgtCy0LjQuCDRgSDQutC+0YLQvtGA0YvQvNC4INC80L7QttC90L4g0L/QvtC00LHQuNGA0LDRgtGMINGC0LXRgNCw0L/QtdCy0YLQuNGH0LXRgdC60LjQtSDQsNCz0LXQvdGC0YsuINCc0LXRgtC+0LTQvtCyLCDQuNC30LzQtdGA0Y/RjtGJ0LjRhSDQvNC10YLQuNC70LjRgNC+0LLQsNC90LjQtSDQlNCd0JosINC40LfQvtCx0YDQtdGC0LXQvdC+INCx0L7Qu9GM0YjQvtC1INC60L7Qu9C40YfQtdGB0YLQstC+LiDQkiDRjdGC0L7QvCDQvNCw0YHRgtC10YAt0LrQu9Cw0YHRgdC1INC80Ysg0L/QvtCz0L7QstC+0YDQuNC8INC+INCx0LjRgdGD0LvRjNGE0LjRgtC90L7QvCDRgdC10LrQstC10L3QuNGA0L7QstCw0L3QuNC4INGBINGD0LzQtdC90YzRiNC10L3QvdC+0Lkg0L/RgNC10LTRgdGC0LDQstC70LXQvdC90L7RgdGC0YzRjiAoUmVkdWNlZCBSZXByZXNlbnRhdGlvbiBCaXN1bGZpdGUgU2VxdWVuY2luZywgUlJCUykuCgoqKirQktC90LjQvNCw0L3QuNC1Kio6KiDQvNC10YLQvtC00Ysg0Lgg0L/QvtC00YXQvtC00YssINGA0LDRgdGB0LrQsNC30YvQstCw0LXQvNGL0LUg0LIg0Y3RgtC+0Lwg0LHQu9C+0LrQvdC+0YLQtSDRgtCw0LrQttC1INC/0YDQuNC80LXQvdC40LzRiyDQuiDQv9C+0LvQvdC+0LPQtdC90L7QvNC90L7QvNGDINCx0LjRgdGD0LvRjNGE0LjRgtC90L7QvNGDINGB0LXQutCy0LXQvdC40YDQvtCy0LDQvdC40Y4gKFdob2xlIEdlbm9tZSBCaXN1bGZpdGUgU2VxdWVuY2luZywgV0dCUykuINCU0LDQvdC90YvQuSDQsdC70L7QutC90L7RgiDQvdC1INC/0YDQtdGC0LXQvdC00YPQtdGCINC90LAg0LjRgdGC0LjQvdGDINCyINC/0L7RgdC70LXQtNC90LXQuSDQuNC90YHRgtCw0L3RhtC40LguINCh0YPRidC10YHRgtCy0YPRjtGCINCw0LvRjNGC0LXRgNC90LDRgtC40LLQvdGL0LUg0L/QvtC00YXQvtC00Ysg0Log0LDQvdCw0LvQuNC30YMg0Lgg0YHQvtC+0YLQstC10YLRgdGC0LLRg9GO0YnQuNC1INC/0YDQvtCz0YDQsNC80LzRiyDQuCDQsdC40LHQu9C40L7RgtC10LrQuC4KCiMgUlJCUwoKUlJCUyAtINCx0LjRgdGD0LvRjNGE0LjRgtC90L7QtSDRgdC10LrQstC10L3QuNGA0L7QstCw0L3QuNC1INGBINGD0LzQtdC90YzRiNC10L3QvdC+0Lkg0L/RgNC10LTRgdGC0LDQstC70LXQvdC90L7RgdGC0YzRji4g0J7QvdC+INCx0L7Qu9C10LUg0LTQtdGI0LXQstC+0LUsINGH0LXQvCDRgdC10LrQstC10L3QuNGA0L7QstCw0L3QuNC1INC/0L7Qu9C90L7Qs9C+INCz0LXQvdC+0LzQsCwg0L3QviDQtNCw0ZHRgiDQuNC90YTQvtGA0LzQsNGG0LjRjiDQsdC+0LvQtdC1LCDRh9C10Lwg0L4gODAlIENwRyDQvtGB0YLRgNC+0LLQutCw0YUg0YfQtdC70L7QstC10YfQtdGB0LrQvtCz0L4g0LPQtdC90L7QvNCwLiDQlNC+0YHRgtC40LPQsNC10YLRgdGPINGN0YLQvtGCINGN0YTRhNC10LrRgiDQt9CwINGB0YfRkdGCINC+0LHQvtCz0LDRidC10L3QuNGPINCx0LjQsdC70LjQvtGC0LXQutC4INGB0L/QtdGG0LjQsNC70YzQvdGL0LzQuCDRgNC10YHRgtGA0LjQutGC0LDQt9Cw0LzQuCAoTXNwSSwgWG1hSSkuCgrQkdC40LHQu9C40L7RgtC10LrQuCDQsiDQv9GA0L7RhtC10YHRgdC1INC/0L7QtNCz0L7RgtC+0LLQutC4INC6INGB0LXQutCy0LXQvdC40YDQvtCy0LDQvdC40Y4g0L/QvtC00LLQtdGA0LPQsNGO0YIg0LHQuNGB0YPQu9GM0YTQuNGC0L3QvtC5INC60L7QvdCy0LXRgNGB0LjQuCwg0YIu0LUuINC+0LHRgNCw0LHQsNGC0YvQstCw0Y7RgiDRgNCw0YHRgtCy0L7RgNC+0LwgTmFIU09+M34gLiDQodGD0YLRjCDRjdGC0L7Qs9C+INGI0LDQs9CwLCDQv9GA0LXQtNGB0YLQsNCy0LvQtdC90LAg0L3QsCDRgNC40YHRg9C90LrQtSBcQHJlZihmaWc6YmlzdWxmaXRlKS4g0J3QtdC80LXRgtC40LvQuNGA0L7QstCw0L3QvdGL0LUg0YbQuNGC0L7Qt9C40L3RiyDQv9GA0Lgg0L7QsdGA0LDQsdC+0YLQutC1INCx0LjRgdGD0LvRjNGE0LjRgtC+0Lwg0L3QsNGC0YDQuNGPINC+0LrQuNGB0LvRj9GO0YLRgdGPINC00L4g0YPRgNCw0YbQuNC70LAsINC60L7RgtC+0YDRi9C5INC/0YDQuCDQn9Cm0KAg0LfQsNC80LXQvdGP0LXRgtGB0Y8g0L3QsCDRgtC40LzQuNC9LiDQntC00L3QsNC60L4g0YLQsNC60L7QvNGDINC90LUg0L/QvtC00LLQtdGA0LbQtdC90Ysg0LzQtdGC0LjQu9C40YDQvtCy0LDQvdC90YvQtSDRhtC40YLQvtC30LjQvdGLLiDQodC70LXQtNC+0LLQsNGC0LXQu9GM0L3Qviwg0L3QsCDRgtC+0Lwg0LzQtdGB0YLQtSwg0LPQtNC1INGB0LXQutCy0LXQvdCw0YLQvtGA0L7QvCDQv9C+0LvRg9GH0LXQvSDRgtC40LzQuNC9LCDQsdGL0Lsg0L3QtdC80LXRgtC40LvQuNGA0L7QstCw0L3QvdGL0Lkg0YbQuNGC0L7Qt9C40L0sINCwINC/0YDQvtGG0LjRgtCw0L3QvdGL0LUg0YbQuNGC0L7Qt9C40L3RiyAtINC80LXRgtC40LvQuNGA0L7QstCw0L3QvdGL0LUuINCi0LDQutC40Lwg0L7QsdGA0LDQt9C+0LwsINC80L7QttC90L4g0LjQt9C80LXRgNGP0YLRjCDRg9GA0L7QstC10L3RjCDQvNC10YLQuNC70LjRgNC+0LLQsNC90LjRjyDQsiDQutC+0L3QutGA0LXRgtC90L7QvCDQu9C+0LrRg9GB0LUg0JTQndCaLgoKIVvQkdC40YHRg9C70YzRhNC40YLQvdCw0Y8g0LrQvtC90LLQtdGA0YHQuNGPXShiaXN1bGZpdGUtY29udmVyc2lvbi5wbmcpeyNmaWctYmlzdWxmaXRlfQoK0KPRgNC+0LLQtdC90Ywg0LzQtdGC0LjQu9C40YDQvtCy0LDQvdC40Y8g0YDQsNGB0YHRh9C40YLRi9Cy0LDQtdGC0YHRjyDQv9C+INGB0LvQtdC00YPRjtGJ0LXQuSDRhNC+0YDQvNGD0LvQtToKCiQkCm1ldGh5bGF0aW9uID0gXGZyYWN7Q317QytUfQokJAoKIyDQkNC90LDQu9C40Lcg0LTQsNC90L3Ri9GFCgrQn9C+0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L7RgdGC0Ywg0L7QsdGA0LDQsdC+0YLQutC4INC00LDQvdC90YvRhSDQv9GA0LXQtNGB0YLQsNCy0LvQtdC90LAg0YDQuNGB0YPQvdC60LUgXEByZWZ7ZmlnOndvcmtmbG93fSBbQHdyZWN6eWNrYTIwMTddLgoKIVvQmtC+0L3QstC10LnQtdGAINCw0L3QsNC70LjQt9CwINC00LDQvdC90YvRhSBSUkJTXSh3b3JrZmxvdy5qcGcpeyNmaWctd29ya2Zsb3d9CgrQmtC+0L3RgtGA0L7Qu9GMINC60LDRh9C10YHRgtCy0LAg0L7RgdGD0YnQtdGB0YLQstC70Y/QtdGC0YHRjyDRgSDQv9C+0LzQvtGJ0YzRjiDRgdGC0LDQvdC00LDRgNGC0L3QvtC5INC/0YDQvtCz0YDQsNC80LzRiyBGYXN0UUMuCgpgYGB7cn0KbGlicmFyeShEaWFncmFtbWVSKQptZXJtYWlkKCIKZ3JhcGggTFIKICAgIEF7fS0tPkIKIikKYGBgCgojIyDQn9C+0LTQs9C+0YLQvtCy0LrQsCDQuiDRgNCw0LHQvtGC0LUKCmBgYHtyIGV2YWw9Rn0KaWYgKCFyZXF1aXJlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKCkJpb2NNYW5hZ2VyOjppbnN0YWxsKGMoIkdFT3F1ZXJ5IiwibGltbWEiLCAiZWRnZVIiLCAibWV0aHlsS2l0IiwgIkRNUmNhdGUiKSkKaW5zdGFsbC5wYWNrYWdlcyhjKCJzdHJpbmdyIiwgInBseXIiKSkKYGBgCgojIyDQmNC80L/QvtGA0YIg0L/QsNC60LXRgtC+0LIKCmBgYHtyIGVjaG89VCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShHRU9xdWVyeSkKbGlicmFyeShsaW1tYSkKbGlicmFyeShlZGdlUikKbGlicmFyeShtZXRoeWxLaXQpCmxpYnJhcnkoRE1SY2F0ZSkKbGlicmFyeShkb1BhcmFsbGVsKQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoc3RyaW5ncikKYGBgCgojIyDQl9Cw0LPRgNGD0LfQutCwINC00LDQvdC90YvRhQoKYGBge3J9CiMg0KfRgtC+0LHRiyDQt9Cw0LPRgNGD0LfQutCwINC90LUg0L/QsNC00LDQu9CwINC40Lct0LfQsCDQstGA0LXQvNC10L3QvdC+0LPQviDQvtCz0YDQsNC90LjRh9C10L3QuNGPINC90LAg0L7QsdC80LXQvSDQvNC10LbQtNGDINGB0LXRgNCy0LXRgNC+0Lwg0Lgg0LrQu9C40LXQvdGC0L7QvCAo0LLQsNC80LgpCm9wdGlvbnModGltZW91dCA9IG1heCgzMDAsIGdldE9wdGlvbigidGltZW91dCIpKSkKb3B0aW9ucyhkb3dubG9hZC5maWxlLm1ldGhvZC5HRU9xdWVyeSA9ICJ3Z2V0IikKCmV4cGVyaW1lbnQgPSBHRU9xdWVyeTo6Z2V0R0VPKCJHU0UxMjI3OTkiKVtbMV1dCnBoZW5vdHlwZXMgPSBCaW9iYXNlOjpwRGF0YShleHBlcmltZW50KQpHRU9xdWVyeTo6Z2V0R0VPU3VwcEZpbGVzKCJHU0UxMjI3OTkiKQoKIyDQlNC70Y8g0YLRj9C20LXQu9GL0YUg0LLRi9GH0LjRgdC70LXQvdC40LkKcHJpbnQocGFzdGUoItCa0L7Quy3QstC+IENQVSIscGFyYWxsZWw6OmRldGVjdENvcmVzKCkpKQpkb1BhcmFsbGVsOjpyZWdpc3RlckRvUGFyYWxsZWwoY29yZXM9cGFyYWxsZWw6OmRldGVjdENvcmVzKCktMikKYGBgCgpgYGB7cn0KdW50YXIoIkdTRTEyMjc5OS9HU0UxMjI3OTlfUkFXLnRhciIsIGV4ZGlyID0gIkdTRTEyMjc5OS8iKQpmaWxlcyA9IFN5cy5nbG9iKCJHU0UxMjI3OTkvKi5iaXNtYXJrLmNvdi5neiIpCmBgYAoKYGBge3J9CnNhbXBsZS5pbmNsdWRlID0gd2hpY2gocGhlbm90eXBlcyRjaGFyYWN0ZXJpc3RpY3NfY2gxLjIgPT0gIm10eXBlaGU6IGhpSEVSIiB8IHBoZW5vdHlwZXMkY2hhcmFjdGVyaXN0aWNzX2NoMS4yID09ICJtdHlwZWhlOiBoaUx1bUFCIikKcGhlbm90eXBlczEgPSBwaGVub3R5cGVzW3NhbXBsZS5pbmNsdWRlLCBdCmZpbGVzMSA9IGZpbGVzW3NhbXBsZS5pbmNsdWRlXQpgYGAKCmBgYHtyIGluY2x1ZGUgPSBGfQpyYXdfZGF0YSA9IG1ldGhSZWFkKGxvY2F0aW9uID0gYXMubGlzdChmaWxlczEpLAogICAgICAgICAgICAgICBwaXBlbGluZSA9ICJiaXNtYXJrQ292ZXJhZ2UiLAogICAgICAgICAgICAgICBzYW1wbGUuaWQ9YXMubGlzdChwaGVub3R5cGVzMSRnZW9fYWNjZXNzaW9uKSwKICAgICAgICAgICAgICAgYXNzZW1ibHk9ImhnMTkiLAogICAgICAgICAgICAgICB0cmVhdG1lbnQgPSBpZmVsc2UocGhlbm90eXBlczEkY2hhcmFjdGVyaXN0aWNzX2NoMS4yID09ICJtdHlwZWhlOiBoaUhFUiIsIDEsIDApLAogICAgICAgICAgICAgICBjb250ZXh0PSJDcEciKQpgYGAKCiMjINCe0L/QuNGB0LDRgtC10LvRjNC90LDRjyDRgdGC0LDRgtC40YHRgtC40LrQsAoKYGBge3J9CmdldE1ldGh5bGF0aW9uU3RhdHMocmF3X2RhdGFbWzJdXSxwbG90PVRSVUUsYm90aC5zdHJhbmRzPUZBTFNFKQpgYGAKCmBgYHtyfQpnZXRDb3ZlcmFnZVN0YXRzKHJhd19kYXRhW1syXV0scGxvdD1UUlVFLGJvdGguc3RyYW5kcz1GQUxTRSkKYGBgCgpgYGB7ciBldmFsPUZ9CmZvciAoc2FtcGxlIGluIHJhd19kYXRhKSB7CiAgZ2V0TWV0aHlsYXRpb25TdGF0cyhzYW1wbGUscGxvdD1UUlVFLGJvdGguc3RyYW5kcz1GQUxTRSkKICBTeXMuc2xlZXAoNSkKfQpgYGAKCmBgYHtyfQpmaWx0ZXJlZCA9IGZpbHRlckJ5Q292ZXJhZ2UocmF3X2RhdGEsbG8uY291bnQ9MTAsbG8ucGVyYz1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpLmNvdW50PU5VTEwsaGkucGVyYz05OS41KQpgYGAKCiMjINCe0LHRitC10LTQuNC90LXQvdC40LUg0YDQtdC30YPQu9GM0YLQsNGC0L7QsgoKYGBge3J9Cm1ldGg9bWV0aHlsS2l0Ojp1bml0ZShmaWx0ZXJlZCwgZGVzdHJhbmQ9RkFMU0UsbWluLnBlci5ncm91cCA9IDEwTCwgbWMuY29yZXMgPSAzMCkKI2xvYWQoIlVuaXRlX21ldGguUkRhdGEiKQpgYGAKCiMjINCk0LjQu9GM0YLRgNCw0YbQuNGPCgpgYGB7cn0KbWV0aE1hdHJpeCA9IHBlcmNNZXRoeWxhdGlvbihtZXRoLHJvd2lkcyA9IFQpCnNkcz1tYXRyaXhTdGF0czo6cm93U2RzKG1ldGhNYXRyaXgsbmEucm0gPSBUKQpwcmludChkaW0obWV0aE1hdHJpeCkpCmhpc3Qoc2RzLGNvbD0iY29ybmZsb3dlcmJsdWUiLHhsYWI9IlN0ZC4gZGV2LiBwZXIgQ3BHIiwgYnJlYWtzID0gNTApCmBgYAoKYGBge3J9CmRpbShtZXRoKQpgYGAKCmBgYHtyfQptZXRoLmZpbHQgPSBtZXRoW3NkcyA+IDEwLF0KYGBgCgpgYGB7cn0KZGltKG1ldGguZmlsdCkKYGBgCgpgYGB7cn0Kc2hhcmVkID0gd2l0aCgKICBsaXN0KHh4ID0gaWZlbHNlKGlzLm5hKG1ldGhNYXRyaXgpLCAwLCAxKSwgbiA9IG5jb2wobWV0aE1hdHJpeCkpLAogIGxkcGx5KAogICAgMToobi0xKSwKICAgIGZ1bmN0aW9uKGkpCiAgICB7CiAgICAgICMg0L/QvtGB0YLRgNC+0LjQvCDRgdC/0LjRgdC+0Log0LrQsNC20LTRi9C5LdGBLdC60LDQttC00YvQvAogICAgICBkZHBseSgKICAgICAgICBkYXRhLmZyYW1lKCJpIj1yZXAoaSwgbi1pKSwgImoiPShpKzEpOm4pLAogICAgICAgIGMoImkiLCJqIiksCiAgICAgICAgZnVuY3Rpb24ocm93KXsKICAgICAgICAgIGkgPC0gcm93WzEsMV07IGogPC0gcm93WzEsMl07CiAgICAgICAgICBzdW0oeHhbLGldICogeHhbLGpdKTsKICAgICAgICB9KTsKICAgIH0sLnBhcmFsbGVsPVRSVUUpKQpwcmludChzaGFyZWRbc2hhcmVkJFYxIDw9IDEwMDAwLF0pCmBgYAoKYGBge3J9Cm1pc3MgPSAgZnVuY3Rpb24oeCl7CiAgc3VtKGlzLm5hKHgpKS8oc3VtKCFpcy5uYSh4KSkrc3VtKGlzLm5hKHgpKSk7Cn0KCm1ldGguZmlsdC5tYXQgPSBwZXJjTWV0aHlsYXRpb24obWV0aC5maWx0KQptaXNzX3ggPC0gbWlzcyhtZXRoTWF0cml4KTsKbWF4X21pc3MgPSAwLjIKd2hpbGUgKG1pc3NfeCA+IG1heF9taXNzKSB7CiAgeHggPSBpZmVsc2UoaXMubmEobWV0aC5maWx0KSwgMCwgMSk7CiAgCiAgIyDQsiDRgdC60L7Qu9GM0LrQuNGFINC+0LHRgNCw0LfRhtCw0YUg0LXRgdGC0Ywg0LTQsNC90L3Ri9C1INC/0L4g0LrQsNC20LTQvtC80YMg0LvQvtC60YPRgdGDCiAgY3ZyZ19jID0gYXBwbHkoeHgsIDEsIHN1bSk7CiAgY3ZyZ19jX21lYW4gPSBtZWFuKGN2cmdfYyk7CiAgY3ZyZ19jX3NkID0gc2QoY3ZyZ19jKTsKICBmaWx0ZXJfb3V0X3BsYW4gPSBucm93KG1ldGguZmlsdCkqKG1pc3NfeCAtIG1heF9taXNzKTsKICAKICBjdnJnX2NfdGhyc2ggPSBjdnJnX2NbdGFpbChoZWFkKG9yZGVyKGN2cmdfYyksIGZpbHRlcl9vdXRfcGxhbikgLDEpXTsKICBjdnJnX2NfZmx0ID0gY3ZyZ19jIDw9IGN2cmdfY190aHJzaDsKICAKICBtZXRoLmZpbHQgPSBtZXRoLmZpbHRbIWN2cmdfY19mbHQsIF07CiAgbWV0aC5maWx0Lm1hdCA9IHBlcmNNZXRoeWxhdGlvbihtZXRoLmZpbHQpCiAgbWlzc194ID0gbWlzcyhtZXRoLmZpbHQpOwogIAogIGNhdChzcHJpbnRmKAogICAgIkZpbHRlcnMgb3V0OiAjcGxhbj0lZiwgI2ZhY3Q9JWQgQ3BHcyAgPT0+ICBEaW06ICVkIHggJWQgKHNhbXBsZXMgeCBDcEdzKTsgbWlzcyh4KSA9ICUuNGYgXG4iLAogICAgZmlsdGVyX291dF9wbGFuLCBzdW0oY3ZyZ19jX2ZsdCksIGRpbShtZXRoLmZpbHQubWF0KVsyXSwgZGltKG1ldGguZmlsdC5tYXQpWzFdLCBtaXNzX3ggKSk7Cn0KYGBgCgojIyDQkNC90LDQu9C40Lcg0L/QvtGB0LvQtSDRhNC40LvRjNGC0YDQsNGG0LjQuAoKYGBge3IgZXZhbD1GQUxTRX0KcG5nKHdpZHRoID0gMjQwMCwgaGVpZ2h0ID0gMjQwMCwgZmlsZW5hbWUgPSAiY29ycmVsYXRpb24ucG5nIikKZ2V0Q29ycmVsYXRpb24obWV0aC5maWx0LCBwbG90ID0gVCkKZGV2Lm9mZigpCmBgYAoKIVvQmtC+0YDRgNC10LvRj9GG0LjRjyDRg9GA0L7QstC90Y8g0LzQtdGC0LjQu9C40YDQvtCy0LDQvdC40Y8g0LzQtdC20LTRgyDQvtCx0YDQsNC30YbQsNC80LhdKGNvcnJlbGF0aW9uLnBuZykKCmBgYHtyfQpQQ0FTYW1wbGVzKG1ldGguZmlsdCkKYGBgCgpgYGB7cn0KUENBU2FtcGxlcyhtZXRoLmZpbHQsIHNjcmVlcGxvdCA9IFQpCmBgYAoKYGBge3J9CnRyZWUgPSBjbHVzdGVyU2FtcGxlcyhtZXRoLmZpbHQsIGRpc3QgPSAiY29ycmVsYXRpb24iLCBtZXRob2Q9IndhcmQuRDIiKQpyZWN0LmhjbHVzdCh0cmVlLCBrID0gMiwgYm9yZGVyID0gImRhcmtncmVlbiIpCmBgYAoKIyMgRE1SCgpgYGB7cn0KbWV0aC5kaWZmID0gY2FsY3VsYXRlRGlmZk1ldGgobWV0aC5maWx0LCBvdmVyZGlzcGVyc2lvbiA9ICJNTiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGp1c3QgPSAiZmRyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAiRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1jLmNvcmVzID0gMzApCmBgYAoKYGBge3J9Cm1ldGguZGlmZiRkaWYubWV0ID0gaWZlbHNlKG1ldGguZGlmZiRtZXRoLmRpZmYgPD0gLTIwICYgbWV0aC5kaWZmJHF2YWx1ZSA8PSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAiSFlQTyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtZXRoLmRpZmYkbWV0aC5kaWZmID49IDIwICYgbWV0aC5kaWZmJHF2YWx1ZSA8PSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhZUEVSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOTyIpKQptZXRoeWxLaXQ6OmJlZGdyYXBoKG1ldGguZGlmZiwibWV0aF9kaWZmLmJlZGdyYXBoIixjb2wubmFtZSA9ICJtZXRoLmRpZmYiKQoKc2lnbmlmLmRpZmYgPSBnZXRNZXRoeWxEaWZmKG1ldGguZGlmZixxdmFsdWUgPSAwLjA1LCBkaWZmZXJlbmNlID0gMjApCmBgYAoKYGBge3J9CmRpZmYuZGYgPSBkby5jYWxsKGNiaW5kLmRhdGEuZnJhbWUsIG1ldGguZGlmZkAuRGF0YSkKY29sbmFtZXMoZGlmZi5kZikgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInN0cmFuZCIsICJwdmFsdWUiLCAicXZhbHVlIiwgIm1ldGguZGlmZiIsICJkaWYubWV0IikKZ2dwbG90KGRhdGE9ZGlmZi5kZiwgYWVzKHg9bWV0aC5kaWZmLCB5PS1sb2cxMChwdmFsdWUpLCBjb2w9ZGlmLm1ldCkpICsKICBnZW9tX3BvaW50KCkgKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiSFlQTyI9ImJsdWUiLCAiTk8iPSJibGFjayIsICJIWVBFUiI9ImdyZWVuIikpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygtMjAsIDIwKSwgY29sPSJyZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS1sb2cxMCgwLjA1KSwgY29sPSJyZWQiKQoKYGBgCgpgYGB7cn0Kcm93bmFtZXMgPSBwYXN0ZShzaWduaWYuZGlmZiRjaHIsc2lnbmlmLmRpZmYkc3RhcnQsc2lnbmlmLmRpZmYkZW5kLHNlcCA9ICIuIikKY291bnRzLmRpZi5tZXQgPSBwZXJjTWV0aHlsYXRpb24obWV0aC5maWx0LHJvd2lkcyA9IFQpW3Jvd25hbWVzLF0KYW5uX2NvbF9kZiA9IGFzLmRhdGEuZnJhbWUocGhlbm90eXBlczEkY2hhcmFjdGVyaXN0aWNzX2NoMS4yKQpjb2xuYW1lcyhhbm5fY29sX2RmKSA9ICJQaGVub3R5cGUiCmFubl9jb2xfZGYkUGhlbm90eXBlID0gYXMuZmFjdG9yKGFubl9jb2xfZGYkUGhlbm90eXBlKQpsZXZlbHMoYW5uX2NvbF9kZiRQaGVub3R5cGUpID0gYygiaGlIRVIiLCJoaUx1bUFCIikKcm93Lm5hbWVzKGFubl9jb2xfZGYpID0gcGhlbm90eXBlczEkZ2VvX2FjY2Vzc2lvbgphbm5fY29sX2RmCgphbm5fY29sb3JzID0gbGlzdChQaGVub3R5cGUgPSBjKCJoaUhFUiI9InJlZCIsICJoaUx1bUFCIj0ib3JhbmdlIikpCgpwaGVhdG1hcDo6cGhlYXRtYXAoY291bnRzLmRpZi5tZXQsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCJjeWFuIiwgImJsdWUiKSkoMTAwKSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJtYW5oYXR0YW4iLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gIm1hbmhhdHRhbiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNjYWxlID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5fY29sX2RmLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5fY29sb3JzLAogICAgICAgICAgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSAxMDAsCiAgICAgICAgICAgICAgICAgICB0cmVlaGVpZ2h0X2NvbCA9IDc1KQpgYGAKCmBgYHtyfQpyZXF1aXJlKGdlbm9tYXRpb24pCmdlbmUub2JqPXJlYWRUcmFuc2NyaXB0RmVhdHVyZXMoInJlZnNlcS5oZzE5LmJlZC50eHQiKQpnZW5lLnBhcnRzID0gYW5ub3RhdGVXaXRoR2VuZVBhcnRzKGFzKHNpZ25pZi5kaWZmLCJHUmFuZ2VzIiksZ2VuZS5vYmopCgoKY3BnLm9iaj1yZWFkRmVhdHVyZUZsYW5rKCJjcGdpLmhnMTkuYmVkLnR4dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlLmZsYW5rLm5hbWU9YygiQ3BHaSIsInNob3JlcyIpKQpkaWZmQ3BHYW5uPWFubm90YXRlV2l0aEZlYXR1cmVGbGFuayhhcyhzaWduaWYuZGlmZiwiR1JhbmdlcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcGcub2JqJENwR2ksY3BnLm9iaiRzaG9yZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmUubmFtZT0iQ3BHaSIsZmxhbmsubmFtZT0ic2hvcmVzIikKYGBgCgpgYGB7cn0KCmxpYnJhcnkoIm9yZy5Icy5lZy5kYiIpCnByb21vdGVycyA9IGdlbmUucGFydHNAZGlzdC50by5UU1NbZ2VuZS5wYXJ0c0BtZW1iZXJzWywxXSA9PSAxLF0KY29scyA8LSBjKCJFTlRSRVpJRCIsIkdFTkVOQU1FIiwiU1lNQk9MIiwgIkdFTkVOQU1FIikKYW5ub3RhdGlvbiA9IEFubm90YXRpb25EYmk6OnNlbGVjdChvcmcuSHMuZWcuZGIsIGtleXM9dW5pcXVlKHByb21vdGVycyRmZWF0dXJlLm5hbWUpLCBjb2x1bW5zPWNvbHMsIGtleXR5cGU9IlJFRlNFUSIpCmNvb3JkX3Byb21vdGVycyA9IGNiaW5kLmRhdGEuZnJhbWUocHJvbW90ZXJzLCBzaWduaWYuZGlmZltwcm9tb3RlcnMkdGFyZ2V0LnJvdyxdKQphbm5vdGF0ZWRfcHJvbW90ZXJzID0gY29vcmRfcHJvbW90ZXJzICU+JSBkcGx5cjo6aW5uZXJfam9pbihhbm5vdGF0aW9uLCBieT1jKCdmZWF0dXJlLm5hbWUnPSdSRUZTRVEnKSkKCndyaXRlLmNzdjIoYW5ub3RhdGVkX3Byb21vdGVycywgZmlsZSA9ICJwcm9tb3RlcnMuY3N2IikKCgpgYGAKClJncmFwaHZpegoKYGBge3J9CmdlbmVzT2ZJbnRlcmVzdCA9IGFubm90YXRlZF9wcm9tb3RlcnMkbWV0aC5kaWZmCm5hbWVzKGdlbmVzT2ZJbnRlcmVzdCkgPSBhbm5vdGF0ZWRfcHJvbW90ZXJzJEVOVFJFWklECmdlbmVzT2ZJbnRlcmVzdCA9IHNvcnQoZ2VuZXNPZkludGVyZXN0LGRlY3JlYXNpbmcgPSBUKQpnbyA8LSBjbHVzdGVyUHJvZmlsZXI6OmVucmljaEdPKGdlbmU9YW5ub3RhdGVkX3Byb21vdGVycyRFTlRSRVpJRCwgCiAgICAgICAgICAgICBvbnQgPSJCUCIsIAogICAgICAgICAgICAga2V5VHlwZSA9ICJFTlRSRVpJRCIsIAogICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4xLCAKICAgICAgICAgICAgIE9yZ0RiID0gb3JnLkhzLmVnLmRiLCAKICAgICAgICAgICAgIHBBZGp1c3RNZXRob2QgPSAiZmRyIiwKICAgICAgICAgICAgIHJlYWRhYmxlID0gVCkKYGBgCgpgYGB7cn0KaGVhZChnbykKYGBgCgpgYGB7cn0KZG90cGxvdChnbykKYGBgCg==